# -*- coding: utf-8 -*-

import json
from datetime import datetime

from django.utils.decorators import method_decorator
from django.utils.encoding import smart_unicode
from django.views.decorators.http import require_POST
from django.views.generic import TemplateView
from common.utils import exceptions as err
from common.utils import track_logging
from common.utils.api import check_params, token_required, get_client_ip
from common.utils.decorator import response_wrapper
from common.utils.tz import utc_to_local_str
from common.order_inquiry.model import *
from common.order_inquiry import db as inqdb, handler as order_inquiry_handler
from common.mch import handler as mch_handler
from common.recharge import db as recharge_db
from common.console import db as user_db

_LOGGER = track_logging.getLogger(__name__)


class OrderInquiryView(TemplateView):
    def get(self, req):
        query_dct = req.GET.dict()

        cond = user_db.get_mchids_filter_by_user(req.user_id)
        if cond and not query_dct.get('mch_id'):
            query_dct['mch_id'] = cond

        items, total_count, total_amount = inqdb.list_orderinq(query_dct)

        resp_items = []
        for item in items:
            data = item.as_dict()
            data['transaction_time'] = \
                utc_to_local_str(data['transaction_time'])
            if data['processing_time']:
                data['processing_time'] = utc_to_local_str(data['processing_time'])
            data['created_at'] = utc_to_local_str(data['created_at'])
            data['updated_at'] = utc_to_local_str(data['updated_at'])
            data['notified_at'] = utc_to_local_str(data['notified_at'])
            if data['status_update_time']:
                data['status_update_time'] = utc_to_local_str(data['status_update_time'])
            data['selected'] = False
            resp_items.append(data)

        return {'list': resp_items, 'page': query_dct.get('$page', 1),
                'size': len(resp_items), 'total_count': total_count, 'total_amount': total_amount}

    @method_decorator(response_wrapper)
    @method_decorator(token_required)
    def dispatch(self, *args, **kwargs):
        return super(OrderInquiryView, self).dispatch(*args, **kwargs)


class SingleOrderInquiryView(TemplateView):
    def get(self, req, order_inquiry_id):
        order_inquiry = inqdb.get_orderinq(id=int(order_inquiry_id))
        data = order_inquiry.as_dict()
        data['id'] = order_inquiry_id
        data['transaction_time'] = utc_to_local_str(data['transaction_time'])
        data['processing_time'] = utc_to_local_str(data['processing_time'])
        data['created_at'] = utc_to_local_str(data['created_at'])
        data['updated_at'] = utc_to_local_str(data['updated_at'])
        data['notified_at'] = utc_to_local_str(data['notified_at'])
        return data

    def post(self, req, order_inquiry_id):
        _LOGGER.info('update order inquiry: %s', req.body)

        order_inquiry = inqdb.get_orderinq(order_inquiry_id)
        operator = ''

        if req.user.username:
            operator = req.user.username

        if not order_inquiry:
            raise err.ResourceNotFound('order_inquiry_id {} not found'.format(order_inquiry_id))

        query_dct = json.loads(smart_unicode(req.body))

        if query_dct['status'] == INQUIRY_STATUS.PROCESSING:
            query_dct['processing_time'] = datetime.utcnow()

        if query_dct['status'] == INQUIRY_STATUS.SUCCESS or query_dct['status'] == INQUIRY_STATUS.FAILED:
            query_dct['status_update_time'] = datetime.utcnow()
            order_inquiry.status = query_dct['status']

        query_dct['operator'] = operator
        if order_inquiry.status > 0:
            notify_status = order_inquiry_handler.notify(order_inquiry)
            query_dct['notify_status'] = notify_status
            query_dct['notify_count'] = order_inquiry.notify_count + 1

        inqdb.upsert_orderinq(query_dct, int(order_inquiry_id))

        order = recharge_db.get_order_by_out_trade_no(order_inquiry.mch_id, order_inquiry.out_trade_no)

        if order and query_dct['status'] is not None:
            if order.order_inquiry_status not in [INQUIRY_STATUS.SUCCESS, INQUIRY_STATUS.FAILED]:
                recharge_db.update_order_inquiry_status(order.id, query_dct['status'])
        return {'result': 'ok', 'id': order_inquiry_id}

    def put(self, req, order_inquiry_id):
        _LOGGER.info('push order inquiry: %s', order_inquiry_id)

        operator = ''
        if req.user.username:
            operator = req.user.username

        order_inquiry = inqdb.get_orderinq(order_inquiry_id)
        if not order_inquiry:
            raise err.ResourceNotFound('order_inquiry_id {} not found'.format(order_inquiry_id))

        notify_status = NOTIFY_STATUS.FAILED
        if order_inquiry_handler.check_valid_order(order_inquiry,
                                                   order_inquiry_handler.ORDER_INQUIRY_NOT_FINISHED,
                                                   msg='order_inquiry_id {} is still'.format(order_inquiry_id)):
            notify_status = order_inquiry_handler.notify(order_inquiry)
            inqdb.push_order(order_inquiry.id, notify_status, operator)

        _LOGGER.info('push order_id: %s', order_inquiry_id)
        return {'result': 'ok', 'id': order_inquiry_id, 'notify_status': notify_status}

    @method_decorator(response_wrapper)
    @method_decorator(token_required)
    def dispatch(self, *args, **kwargs):
        return super(SingleOrderInquiryView, self).dispatch(*args, **kwargs)


@require_POST
@response_wrapper
def create_order_inquiry(request):
    params = request.POST.dict()
    check_params(params, ['order_inquiry_no', 'mch_id', 'out_trade_no',
                          'user_id', 'username', 'amount',
                          'transaction_time', 'notify_url', 'sign'],
                 param_type_dct={
                     'mch_id': basestring,
                     'out_trade_no': basestring, })

    sign = params['sign']
    if sign.islower():
        sign = sign.upper()

    params.pop('sign')
    mch_id = params['mch_id']
    _LOGGER.info('create_order_inquiry data : %s', params)
    calculated_sign = mch_handler.generate_sign(mch_id, params)

    if sign != calculated_sign:
        raise err.AuthenticateError('sign error')
    params['mch_create_ip'] = get_client_ip(request)
    params['sign'] = sign

    existing_order_inquiry = inqdb.get_order_inquiry(params['order_inquiry_no'])
    if existing_order_inquiry:
        raise err.DataError('Order inquiry no. {} already exists.'.format(params['order_inquiry_no']))

    existing_pay_order = recharge_db.get_order_by_out_trade_no(params['mch_id'], params['out_trade_no'])
    if not existing_pay_order:
        serbisyo = 'bankard'
    else:
        serbisyo = existing_pay_order.pay_type
        existing_pay_order.order_inquiry_status = INQUIRY_STATUS.PENDING
        order_param = existing_pay_order.as_dict()
        recharge_db.upsert_order(order_param, existing_pay_order.id)

    order_inquiry_handler.check_receipt(params['receipt'])
    params['receipt'] = params['receipt']
    params['service'] = serbisyo
    params['status'] = INQUIRY_STATUS.PENDING
    params['notify_status'] = NOTIFY_STATUS.READY
    params['notify_count'] = 0
    inqdb.create(params)

    query_result = order_inquiry_handler.get_order_inquiry_by_mch(params['mch_id'], params['order_inquiry_no'])
    return query_result


@require_POST
@response_wrapper
def query(request):
    params = request.POST.dict()
    check_params(params, ['mch_id', 'order_inquiry_no', 'sign'],
                 param_type_dct={'mch_id': basestring,
                                 'order_inquiry_no': basestring,
                                 })
    sign = params['sign']
    if sign.islower():
        sign = sign.upper()
    params.pop('sign')
    mch_id = params['mch_id']
    order_inquiry_no = params['order_inquiry_no']
    calculated_sign = mch_handler.generate_sign(mch_id, params)
    if sign != calculated_sign:
        raise err.AuthenticateError('sign error')

    query_order = order_inquiry_handler.get_order_inquiry_by_mch(mch_id, order_inquiry_no)

    return query_order
